package gdou.gym.sys.order;

import gdou.gym.dao.SpaceTimeMapper;
import gdou.gym.entity.SpaceTime;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.scheduling.annotation.Scheduled;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.annotation.Resource;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;


public class RemainImpl implements Remain {
    @Resource
    private SpaceTimeMapper spaceTimeMapper;
    private final ConcurrentHashMap<Integer, Integer> temp = new ConcurrentHashMap<>();


    @Resource
    private SqlSessionFactory sqlSessionFactory;

    private static boolean update = false;
    private final ConcurrentHashMap<Integer, Integer> remainMap = new ConcurrentHashMap<>();

    @Override
    public Map<Integer, Integer> getRemainMap() {
        return new HashMap<>(remainMap);
    }

    @PostConstruct
    @Override
    public void initRemain() {
        List<SpaceTime> spaceTimes = spaceTimeMapper.initRemain();
        for (SpaceTime no : spaceTimes) {
            remainMap.put(no.getId(), no.getRemain());
        }

    }

    @Override
    public List<Integer> multiGet(Collection<Integer> hashKeys) {
        throw new UnsupportedOperationException();
    }

    @Override
    public void request(Integer id) {
        Integer integer = remainMap.get(id);
        if (integer != null) temp.put(id, remainMap.remove(id));
    }

    @Override
    public void recover(Integer id) {
        remainMap.put(id, temp.get(id));
    }

    @Override
    public void clear(Integer id) {
        remainMap.put(id, 0);
    }

    @Override
    public boolean put(Integer id, Integer count) {
        remainMap.put(id, count);
        update = true;
        return true;
    }

    @Override
    public boolean increase(Integer id, int count) {
        Integer compute = remainMap.compute(id, (k, v) -> {
            if (k == null) return null;
            return v == null ? count : count + v;
        });
        update = true;
        return compute != null;
    }


    @Override
    public boolean putOrIncrease(Integer id, Integer count) {
        remainMap.compute(id, (k, v) -> v == null ? count : count + v);
        update = true;
        return true;
    }

    @Override
    public boolean removeOrDecrease(Integer id, Integer count) {
        Integer compute = remainMap.compute(id, (k, v) -> {
            if (k == null || v == null) return null;
            if (v <= count) return remainMap.remove(id);
            return v - count;
        });
        return compute != null;
    }


    @Override
    public boolean decrease(Integer id, int count) {
        Integer compute = remainMap.compute(id, (k, v) -> {
            if (k == null || v == null || v < count) return null;
            return v - count;
        });
        return compute != null;
    }

    @Override
    public boolean remove(Integer id) {
        return remainMap.remove(id) != null;
    }

    @Override
    public Integer getRemain(Integer id) {
        return remainMap.get(id);
    }

    @Override
    public void batchUpdate() {
        SqlSession session = sqlSessionFactory.openSession(ExecutorType.BATCH);
        SpaceTimeMapper mapper = session.getMapper(SpaceTimeMapper.class);
        for (Map.Entry<Integer, Integer> entry : remainMap.entrySet()) {
            mapper.updateSpaceTimeRemain(entry.getKey(), entry.getValue());
        }
        session.commit();
        session.close();
    }

    @PreDestroy
    public void destroy() {
        update();
    }

    @Scheduled(cron = "0/10 * *  * * ? ")
    public void update() {
        if (update) {
            batchUpdate();
            update = false;
        }
    }


}
